# Copyright (c) 2007 Kimmo Parviainen <kimvais@gmail.com>
# See the LICENSE file for details

import Image,ImageDraw

drawcoordmultipliers = [-0.5,-1,0.5,-1,1,0,0.5,1,-0.5,1,-1,0,-0.5,-1]
colors = [
		"#228822",
		"#22aa22",
		"#22cc22",
		"#22ff22",
		"#ccff00",
		"#ffff00",
		"#ffcf00",
		"#cca800",
		"#ac7e00",
		"#785800",
		"#453300",
		"#5e5e5e",
		"#919191",
		"#c1c1c1",
		"#d9d9d9",
		"#ffffff"]

def north(x,y):
	return x,y-2
def northeast(x,y):
	return (x+y%2),y-1
def southeast(x,y):
	return (x+y%2),y+1
def south(x,y):
	return (x,y+2)
def southwest(x,y):
	return (x-((y+1)%2),y+1)
def northwest(x,y):
	return (x-((y+1)%2),y-1)

directions = [north,northeast,southeast,south,southwest,northwest]

class map:
	def __init__(self,size):
		if size > 7:
			print "That would be HUGE, I'll give you 66177 hexes instead..."
			size = 7
		self.size = 2**size
		self.x = self.size+3
		self.y = self.size*4+7
		self.rivers = []
		self.lake = []
		self.data = [[{'z':-2, 's':0} for col in range(self.y)] for row in range(self.x)]
		self.scale = 20
		print "Initializing an Hex map (size %d (X: %d, Y: %d)" %	(self.size,self.x,self.y)
	
	def get_coords(self,x,y):
		radius = self.scale
		ix = x*3*radius+2*radius
		iy = y*radius
		if (y % 2) == 1:
			ix += 1.5*radius
			iy += 2*radius
		else:
			iy += 2*radius
		return (ix,iy)

	def get_polygon(self,x,y):
		radius = self.scale
		offsets = [i*radius for i in drawcoordmultipliers]
		ix,iy = self.get_coords(x,y)
		ret = []
		for i in range(0,14,2):
			a,b = ix+offsets[i],iy+offsets[i+1]
			ret += (a,b),
		return ret

	def draw(self,scale=15,print_coords=False):
		self.scale=scale
		imxy = self.get_coords(self.x,self.y)
		im = Image.new("RGB",(imxy),"#fff")
		draw = ImageDraw.Draw(im)
		for x in range(self.x):
			for y in range(self.y):
				z = self.data[x][y]['z']
				if z < -1 :
					fillcolor = "#0080FF"
				elif z < 0 or 'd' in self.data[x][y]:
					fillcolor = "#00bfff"
				elif z < len(colors):
					fillcolor = colors[int(z)]
				else:
					fillcolor = "#fff"
				draw.polygon(self.get_polygon(x,y),outline="#000",fill=fillcolor)
				xy = self.get_coords(x,y)
				txtxy = (xy[0]-self.scale/2,xy[1]-5)
				if print_coords:
					draw.text(txtxy,("%d" % self.data[x][y]['z']),fill="#FFF")
		for river in self.rivers:
			width = 1
			while len(river) > 1:
				ax,ay = river.pop(0)
				bx,by = river[0]
				coords = (ax,ay)
				riverline = [self.get_coords(ax,ay),self.get_coords(bx,by)]
				width = min(width+1,4,(16-self.getz(coords)))
				width = max(1,width)
				draw.line(riverline,"#00bfFF",1)
		return im

	def setz(self,coords,z):
		x,y = coords
		self.data[x][y]['z'] = z

	def getz(self,coords):
		x,y = coords
		return self.data[x][y]['z']

	def rise(self,coords,amount):
		x,y = coords
		if x>-1 and y>-1 and x<self.x and y<self.y:
			self.data[x][y]['z'] += amount
		
	def getavgz(self,*coordslist):
		sum = 0
		if len(coordslist)==1 and type(coordslist[0]) == type([]):
			coordslist = coordslist[0]
		for coords in coordslist:
			x,y = coords
			z = self.data[x][y]['z']
			sum += max(-2,z)
		return sum/len(coordslist)
	
	def getminz(self,*coordslist):
		ret = False
		if len(coordslist)==1 and type(coordslist[0]) == type([]):
			coordslist = coordslist[0]
		for coords in coordslist:
			x,y = coords
			z = self.data[x][y]['z']
			if not ret or z < ret[0]:
				ret = (z,coords)
			else:
				continue
		return ret
	
	def getstreams(self,coords):
		x,y = coords
		return self.data[x][y]['s']
	
	def getmaxz(self,*coordslist):
		ret = False
		if len(coordslist)==1 and type(coordslist[0]) == type([]):
			coordslist = coordslist[0]
		for coords in coordslist:
			x,y = coords
			z = self.data[x][y]['z']
			if not ret or z > ret[0]:
				ret = (z,coords)
			else:
				continue
		return ret

	def addstream(self,coords):
		x,y = coords
		self.data[x][y]['s'] += 1
		
	def add_lake(self,coords,z):
		#print "adding lake at",coords,z
		x,y = coords
		self.data[x][y]['d'] = self.getz(coords) 
		self.setz(coords,z)
		self.lake.append(coords)

	def neighbours(self,coords):
		x,y = coords
		ret = []
		for func in directions:
			rx,ry = func(x,y)
			if rx>-1 and rx<self.x and ry>-1 and ry<self.y:
				ret.append((rx,ry))
		return ret
	
